// #include <vulkan/vulkan.h>
// #include <GLFW/glfw3.h>
// #include <iostream>
// #include <vector>
// #include <fstream>
// #include <stdexcept>
// #include <algorithm>
// #include <optional>
// #include <set>

// // 窗口尺寸
// const uint32_t WIDTH = 800;
// const uint32_t HEIGHT = 600;

// // 验证层
// const std::vector<const char*> validationLayers = {
//     "VK_LAYER_KHRONOS_validation"
// };

// // 设备扩展
// const std::vector<const char*> deviceExtensions = {
//     VK_KHR_SWAPCHAIN_EXTENSION_NAME
// };

// #ifdef NDEBUG
// const bool enableValidationLayers = false;
// #else
// const bool enableValidationLayers = true;
// #endif

// // 顶点结构
// struct Vertex {
//     glm::vec2 pos;
//     glm::vec3 color;
//     glm::vec2 texCoord;
// };

// // 顶点数据
// const std::vector<Vertex> vertices = {
//     {{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {0.0f, 0.0f}},
//     {{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {1.0f, 0.0f}},
//     {{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {1.0f, 1.0f}},
//     {{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {0.0f, 1.0f}}
// };

// const std::vector<uint16_t> indices = {
//     0, 1, 2, 2, 3, 0
// };

// // 队列族索引
// struct QueueFamilyIndices {
//     std::optional<uint32_t> graphicsFamily;
//     std::optional<uint32_t> presentFamily;
    
//     bool isComplete() {
//         return graphicsFamily.has_value() && presentFamily.has_value();
//     }
// };

// // 交换链支持详情
// struct SwapChainSupportDetails {
//     VkSurfaceCapabilitiesKHR capabilities;
//     std::vector<VkSurfaceFormatKHR> formats;
//     std::vector<VkPresentModeKHR> presentModes;
// };

// class HelloTriangleApplication {
// public:
//     void run() {
//         initWindow();
//         initVulkan();
//         mainLoop();
//         cleanup();
//     }

// private:
//     GLFWwindow* window;
//     VkInstance instance;
//     VkDebugUtilsMessengerEXT debugMessenger;
//     VkSurfaceKHR surface;
//     VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
//     VkDevice device;
//     VkQueue graphicsQueue;
//     VkQueue presentQueue;
//     VkSwapchainKHR swapChain;
//     std::vector<VkImage> swapChainImages;
//     VkFormat swapChainImageFormat;
//     VkExtent2D swapChainExtent;
//     std::vector<VkImageView> swapChainImageViews;
//     VkRenderPass renderPass;
//     VkDescriptorSetLayout descriptorSetLayout;
//     VkPipelineLayout pipelineLayout;
//     VkPipeline graphicsPipeline;
//     std::vector<VkFramebuffer> swapChainFramebuffers;
//     VkCommandPool commandPool;
//     std::vector<VkCommandBuffer> commandBuffers;
//     std::vector<VkSemaphore> imageAvailableSemaphores;
//     std::vector<VkSemaphore> renderFinishedSemaphores;
//     std::vector<VkFence> inFlightFences;
//     size_t currentFrame = 0;
//     bool framebufferResized = false;
    
//     VkBuffer vertexBuffer;
//     VkDeviceMemory vertexBufferMemory;
//     VkBuffer indexBuffer;
//     VkDeviceMemory indexBufferMemory;
    
//     VkImage textureImage;
//     VkDeviceMemory textureImageMemory;
//     VkImageView textureImageView;
//     VkSampler textureSampler;
    
//     VkDescriptorPool descriptorPool;
//     VkDescriptorSet descriptorSet;
    
//     std::vector<VkBuffer> uniformBuffers;
//     std::vector<VkDeviceMemory> uniformBuffersMemory;
//     std::vector<void*> uniformBuffersMapped;

//     void initWindow() {
//         glfwInit();
//         glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
//         window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
//         glfwSetWindowUserPointer(window, this);
//         glfwSetFramebufferSizeCallback(window, framebufferResizeCallback);
//     }

//     static void framebufferResizeCallback(GLFWwindow* window, int width, int height) {
//         auto app = reinterpret_cast<HelloTriangleApplication*>(glfwGetWindowUserPointer(window));
//         app->framebufferResized = true;
//     }

//     void initVulkan() {
//         createInstance();
//         setupDebugMessenger();
//         createSurface();
//         pickPhysicalDevice();
//         createLogicalDevice();
//         createSwapChain();
//         createImageViews();
//         createRenderPass();
//         createDescriptorSetLayout();
//         createGraphicsPipeline();
//         createFramebuffers();
//         createCommandPool();
//         createTextureImage();
//         createTextureImageView();
//         createTextureSampler();
//         createVertexBuffer();
//         createIndexBuffer();
//         createUniformBuffers();
//         createDescriptorPool();
//         createDescriptorSet();
//         createCommandBuffers();
//         createSyncObjects();
//     }

//     void mainLoop() {
//         while (!glfwWindowShouldClose(window)) {
//             glfwPollEvents();
//             drawFrame();
//         }
//         vkDeviceWaitIdle(device);
//     }

//     void cleanup() {
//         cleanupSwapChain();
        
//         vkDestroySampler(device, textureSampler, nullptr);
//         vkDestroyImageView(device, textureImageView, nullptr);
//         vkDestroyImage(device, textureImage, nullptr);
//         vkFreeMemory(device, textureImageMemory, nullptr);
        
//         vkDestroyDescriptorSetLayout(device, descriptorSetLayout, nullptr);
        
//         vkDestroyBuffer(device, vertexBuffer, nullptr);
//         vkFreeMemory(device, vertexBufferMemory, nullptr);
        
//         vkDestroyBuffer(device, indexBuffer, nullptr);
//         vkFreeMemory(device, indexBufferMemory, nullptr);
        
//         for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
//             vkDestroyBuffer(device, uniformBuffers[i], nullptr);
//             vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
//         }
        
//         vkDestroyDescriptorPool(device, descriptorPool, nullptr);
        
//         for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
//             vkDestroySemaphore(device, renderFinishedSemaphores[i], nullptr);
//             vkDestroySemaphore(device, imageAvailableSemaphores[i], nullptr);
//             vkDestroyFence(device, inFlightFences[i], nullptr);
//         }
        
//         vkDestroyCommandPool(device, commandPool, nullptr);
        
//         vkDestroyDevice(device, nullptr);
        
//         if (enableValidationLayers) {
//             DestroyDebugUtilsMessengerEXT(instance, debugMessenger, nullptr);
//         }
        
//         vkDestroySurfaceKHR(instance, surface, nullptr);
//         vkDestroyInstance(instance, nullptr);
        
//         glfwDestroyWindow(window);
//         glfwTerminate();
//     }

//     void createInstance() {
//         if (enableValidationLayers && !checkValidationLayerSupport()) {
//             throw std::runtime_error("validation layers requested, but not available!");
//         }

//         VkApplicationInfo appInfo{};
//         appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
//         appInfo.pApplicationName = "Hello Triangle";
//         appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
//         appInfo.pEngineName = "No Engine";
//         appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
//         appInfo.apiVersion = VK_API_VERSION_1_0;

//         VkInstanceCreateInfo createInfo{};
//         createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
//         createInfo.pApplicationInfo = &appInfo;

//         auto extensions = getRequiredExtensions();
//         createInfo.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
//         createInfo.ppEnabledExtensionNames = extensions.data();

//         VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo{};
//         if (enableValidationLayers) {
//             createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
//             createInfo.ppEnabledLayerNames = validationLayers.data();
            
//             populateDebugMessengerCreateInfo(debugCreateInfo);
//             createInfo.pNext = (VkDebugUtilsMessengerCreateInfoEXT*) &debugCreateInfo;
//         } else {
//             createInfo.enabledLayerCount = 0;
//             createInfo.pNext = nullptr;
//         }

//         if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create instance!");
//         }
//     }

//     void setupDebugMessenger() {
//         if (!enableValidationLayers) return;

//         VkDebugUtilsMessengerCreateInfoEXT createInfo;
//         populateDebugMessengerCreateInfo(createInfo);

//         if (CreateDebugUtilsMessengerEXT(instance, &createInfo, nullptr, &debugMessenger) != VK_SUCCESS) {
//             throw std::runtime_error("failed to set up debug messenger!");
//         }
//     }

//     void createSurface() {
//         if (glfwCreateWindowSurface(instance, window, nullptr, &surface) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create window surface!");
//         }
//     }

//     void pickPhysicalDevice() {
//         uint32_t deviceCount = 0;
//         vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr);
        
//         if (deviceCount == 0) {
//             throw std::runtime_error("failed to find GPUs with Vulkan support!");
//         }
        
//         std::vector<VkPhysicalDevice> devices(deviceCount);
//         vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data());
        
//         for (const auto& device : devices) {
//             if (isDeviceSuitable(device)) {
//                 physicalDevice = device;
//                 break;
//             }
//         }
        
//         if (physicalDevice == VK_NULL_HANDLE) {
//             throw std::runtime_error("failed to find a suitable GPU!");
//         }
//     }

//     void createLogicalDevice() {
//         QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
        
//         std::vector<VkDeviceQueueCreateInfo> queueCreateInfos;
//         std::set<uint32_t> uniqueQueueFamilies = {indices.graphicsFamily.value(), indices.presentFamily.value()};
        
//         float queuePriority = 1.0f;
//         for (uint32_t queueFamily : uniqueQueueFamilies) {
//             VkDeviceQueueCreateInfo queueCreateInfo{};
//             queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
//             queueCreateInfo.queueFamilyIndex = queueFamily;
//             queueCreateInfo.queueCount = 1;
//             queueCreateInfo.pQueuePriorities = &queuePriority;
//             queueCreateInfos.push_back(queueCreateInfo);
//         }
        
//         VkPhysicalDeviceFeatures deviceFeatures{};
//         deviceFeatures.samplerAnisotropy = VK_TRUE;
        
//         VkDeviceCreateInfo createInfo{};
//         createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
//         createInfo.queueCreateInfoCount = static_cast<uint32_t>(queueCreateInfos.size());
//         createInfo.pQueueCreateInfos = queueCreateInfos.data();
//         createInfo.pEnabledFeatures = &deviceFeatures;
//         createInfo.enabledExtensionCount = static_cast<uint32_t>(deviceExtensions.size());
//         createInfo.ppEnabledExtensionNames = deviceExtensions.data();
        
//         if (enableValidationLayers) {
//             createInfo.enabledLayerCount = static_cast<uint32_t>(validationLayers.size());
//             createInfo.ppEnabledLayerNames = validationLayers.data();
//         } else {
//             createInfo.enabledLayerCount = 0;
//         }
        
//         if (vkCreateDevice(physicalDevice, &createInfo, nullptr, &device) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create logical device!");
//         }
        
//         vkGetDeviceQueue(device, indices.graphicsFamily.value(), 0, &graphicsQueue);
//         vkGetDeviceQueue(device, indices.presentFamily.value(), 0, &presentQueue);
//     }

//     void createSwapChain() {
//         SwapChainSupportDetails swapChainSupport = querySwapChainSupport(physicalDevice);
        
//         VkSurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats);
//         VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes);
//         VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities);
        
//         uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1;
//         if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) {
//             imageCount = swapChainSupport.capabilities.maxImageCount;
//         }
        
//         VkSwapchainCreateInfoKHR createInfo{};
//         createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
//         createInfo.surface = surface;
//         createInfo.minImageCount = imageCount;
//         createInfo.imageFormat = surfaceFormat.format;
//         createInfo.imageColorSpace = surfaceFormat.colorSpace;
//         createInfo.imageExtent = extent;
//         createInfo.imageArrayLayers = 1;
//         createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
        
//         QueueFamilyIndices indices = findQueueFamilies(physicalDevice);
//         uint32_t queueFamilyIndices[] = {indices.graphicsFamily.value(), indices.presentFamily.value()};
        
//         if (indices.graphicsFamily != indices.presentFamily) {
//             createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
//             createInfo.queueFamilyIndexCount = 2;
//             createInfo.pQueueFamilyIndices = queueFamilyIndices;
//         } else {
//             createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
//             createInfo.queueFamilyIndexCount = 0; // Optional
//             createInfo.pQueueFamilyIndices = nullptr; // Optional
//         }
        
//         createInfo.preTransform = swapChainSupport.capabilities.currentTransform;
//         createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
//         createInfo.presentMode = presentMode;
//         createInfo.clipped = VK_TRUE;
//         createInfo.oldSwapchain = VK_NULL_HANDLE;
        
//         if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create swap chain!");
//         }
        
//         vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr);
//         swapChainImages.resize(imageCount);
//         vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data());
        
//         swapChainImageFormat = surfaceFormat.format;
//         swapChainExtent = extent;
//     }

//     void createImageViews() {
//         swapChainImageViews.resize(swapChainImages.size());
        
//         for (size_t i = 0; i < swapChainImages.size(); i++) {
//             VkImageViewCreateInfo createInfo{};
//             createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
//             createInfo.image = swapChainImages[i];
//             createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
//             createInfo.format = swapChainImageFormat;
//             createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
//             createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
//             createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
//             createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
//             createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
//             createInfo.subresourceRange.baseMipLevel = 0;
//             createInfo.subresourceRange.levelCount = 1;
//             createInfo.subresourceRange.baseArrayLayer = 0;
//             createInfo.subresourceRange.layerCount = 1;
            
//             if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
//                 throw std::runtime_error("failed to create image views!");
//             }
//         }
//     }

//     void createRenderPass() {
//         VkAttachmentDescription colorAttachment{};
//         colorAttachment.format = swapChainImageFormat;
//         colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
//         colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
//         colorAttachment.storeOp = VK_ATTACHMENT_LOAD_OP_STORE;
//         colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
//         colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
//         colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
//         colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
        
//         VkAttachmentReference colorAttachmentRef{};
//         colorAttachmentRef.attachment = 0;
//         colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
        
//         VkSubpassDescription subpass{};
//         subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
//         subpass.colorAttachmentCount = 1;
//         subpass.pColorAttachments = &colorAttachmentRef;
        
//         VkSubpassDependency dependency{};
//         dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
//         dependency.dstSubpass = 0;
//         dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
//         dependency.srcAccessMask = 0;
//         dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
//         dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
        
//         VkRenderPassCreateInfo renderPassInfo{};
//         renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
//         renderPassInfo.attachmentCount = 1;
//         renderPassInfo.pAttachments = &colorAttachment;
//         renderPassInfo.subpassCount = 1;
//         renderPassInfo.pSubpasses = &subpass;
//         renderPassInfo.dependencyCount = 1;
//         renderPassInfo.pDependencies = &dependency;
        
//         if (vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create render pass!");
//         }
//     }

//     void createDescriptorSetLayout() {
//         VkDescriptorSetLayoutBinding uboLayoutBinding{};
//         uboLayoutBinding.binding = 0;
//         uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
//         uboLayoutBinding.descriptorCount = 1;
//         uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
//         uboLayoutBinding.pImmutableSamplers = nullptr;
        
//         VkDescriptorSetLayoutBinding samplerLayoutBinding{};
//         samplerLayoutBinding.binding = 1;
//         samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
//         samplerLayoutBinding.descriptorCount = 1;
//         samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
//         samplerLayoutBinding.pImmutableSamplers = nullptr;
        
//         std::array<VkDescriptorSetLayoutBinding, 2> bindings = {uboLayoutBinding, samplerLayoutBinding};
        
//         VkDescriptorSetLayoutCreateInfo layoutInfo{};
//         layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
//         layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
//         layoutInfo.pBindings = bindings.data();
        
//         if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create descriptor set layout!");
//         }
//     }

//     void createGraphicsPipeline() {
//         auto vertShaderCode = readFile("shaders/vert.spv");
//         auto fragShaderCode = readFile("shaders/frag.spv");
        
//         VkShaderModule vertShaderModule = createShaderModule(vertShaderCode);
//         VkShaderModule fragShaderModule = createShaderModule(fragShaderCode);
        
//         VkPipelineShaderStageCreateInfo vertShaderStageInfo{};
//         vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
//         vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
//         vertShaderStageInfo.module = vertShaderModule;
//         vertShaderStageInfo.pName = "main";
        
//         VkPipelineShaderStageCreateInfo fragShaderStageInfo{};
//         fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
//         fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
//         fragShaderStageInfo.module = fragShaderModule;
//         fragShaderStageInfo.pName = "main";
        
//         VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo};
        
//         auto bindingDescription = Vertex::getBindingDescription();
//         auto attributeDescriptions = Vertex::getAttributeDescriptions();
        
//         VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
//         vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INSTANCE_CREATE_INFO;
//         vertexInputInfo.vertexBindingDescriptionCount = 1;
//         vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
//         vertexInputInfo.vertexAttributeDescriptionCount = static_cast<uint32_t>(attributeDescriptions.size());
//         vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
        
//         VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
//         inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_CREATE_INFO;
//         inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
//         inputAssembly.primitiveRestartEnable = VK_FALSE;
        
//         VkViewport viewport{};
//         viewport.x = 0.0f;
//         viewport.y = 0.0f;
//         viewport.width = (float) swapChainExtent.width;
//         viewport.height = (float) swapChainExtent.height;
//         viewport.minDepth = 0.0f;
//         viewport.maxDepth = 1.0f;
        
//         VkRect2D scissor{};
//         scissor.offset = {0, 0};
//         scissor.extent = swapChainExtent;
        
//         VkPipelineViewportStateCreateInfo viewportState{};
//         viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
//         viewportState.viewportCount = 1;
//         viewportState.pViewports = &viewport;
//         viewportState.scissorCount = 1;
//         viewportState.pScissors = &scissor;
        
//         VkPipelineRasterizationStateCreateInfo rasterizer{};
//         rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
//         rasterizer.depthClampEnable = VK_FALSE;
//         rasterizer.rasterizerDiscardEnable = VK_FALSE;
//         rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
//         rasterizer.lineWidth = 1.0f;
//         rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
//         rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
//         rasterizer.depthBiasEnable = VK_FALSE;
        
//         VkPipelineMultisampleStateCreateInfo multisampling{};
//         multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
//         multisampling.sampleShadingEnable = VK_FALSE;
//         multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
        
//         VkPipelineColorBlendAttachmentState colorBlendAttachment{};
//         colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
//         colorBlendAttachment.blendEnable = VK_FALSE;
        
//         VkPipelineColorBlendStateCreateInfo colorBlending{};
//         colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
//         colorBlending.logicOpEnable = VK_FALSE;
//         colorBlending.logicOp = VK_LOGIC_OP_COPY;
//         colorBlending.attachmentCount = 1;
//         colorBlending.pAttachments = &colorBlendAttachment;
//         colorBlending.blendConstants[0] = 0.0f;
//         colorBlending.blendConstants[1] = 0.0f;
//         colorBlending.blendConstants[2] = 0.0f;
//         colorBlending.blendConstants[3] = 0.0f;
        
//         VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
//         pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
//         pipelineLayoutInfo.setLayoutCount = 1;
//         pipelineLayoutInfo.pSetLayouts = &descriptorSetLayout;
//         pipelineLayoutInfo.pushConstantRangeCount = 0;
        
//         if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create pipeline layout!");
//         }
        
//         VkGraphicsPipelineCreateInfo pipelineInfo{};
//         pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
//         pipelineInfo.stageCount = 2;
//         pipelineInfo.pStages = shaderStages;
//         pipelineInfo.pVertexInputState = &vertexInputInfo;
//         pipelineInfo.pInputAssemblyState = &inputAssembly;
//         pipelineInfo.pViewportState = &viewportState;
//         pipelineInfo.pRasterizationState = &rasterizer;
//         pipelineInfo.pMultisampleState = &multisampling;
//         pipelineInfo.pDepthStencilState = nullptr;
//         pipelineInfo.pColorBlendState = &colorBlending;
//         pipelineInfo.pDynamicState = nullptr;
//         pipelineInfo.layout = pipelineLayout;
//         pipelineInfo.renderPass = renderPass;
//         pipelineInfo.subpass = 0;
//         pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
//         pipelineInfo.basePipelineIndex = -1;
        
//         if (vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &graphicsPipeline) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create graphics pipeline!");
//         }
        
//         vkDestroyShaderModule(device, fragShaderModule, nullptr);
//         vkDestroyShaderModule(device, vertShaderModule, nullptr);
//     }

//     void createFramebuffers() {
//         swapChainFramebuffers.resize(swapChainImageViews.size());
        
//         for (size_t i = 0; i < swapChainImageViews.size(); i++) {
//             VkImageView attachments[] = {
//                 swapChainImageViews[i]
//             };
            
//             VkFramebufferCreateInfo framebufferInfo{};
//             framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
//             framebufferInfo.renderPass = renderPass;
//             framebufferInfo.attachmentCount = 1;
//             framebufferInfo.pAttachments = attachments;
//             framebufferInfo.width = swapChainExtent.width;
//             framebufferInfo.height = swapChainExtent.height;
//             framebufferInfo.layers = 1;
            
//             if (vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapChainFramebuffers[i]) != VK_SUCCESS) {
//                 throw std::runtime_error("failed to create framebuffer!");
//             }
//         }
//     }

//     void createCommandPool() {
//         QueueFamilyIndices queueFamilyIndices = findQueueFamilies(physicalDevice);
        
//         VkCommandPoolCreateInfo poolInfo{};
//         poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
//         poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
//         poolInfo.queueFamilyIndex = queueFamilyIndices.graphicsFamily.value();
        
//         if (vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create command pool!");
//         }
//     }

//     void createTextureImage() {
//         int texWidth, texHeight, texChannels;
//         stbi_uc* pixels = stbi_load("textures/texture.jpg", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
//         VkDeviceSize imageSize = texWidth * texHeight * 4;
        
//         if (!pixels) {
//             throw std::runtime_error("failed to load texture image!");
//         }
        
//         VkBuffer stagingBuffer;
//         VkDeviceMemory stagingBufferMemory;
//         createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
        
//         void* data;
//         vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data);
//         memcpy(data, pixels, static_cast<size_t>(imageSize));
//         vkUnmapMemory(device, stagingBufferMemory);
        
//         stbi_image_free(pixels);
        
//         createImage(texWidth, texHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
        
//         transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
//         copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(texWidth), static_cast<uint32_t>(texHeight));
//         transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
        
//         vkDestroyBuffer(device, stagingBuffer, nullptr);
//         vkFreeMemory(device, stagingBufferMemory, nullptr);
//     }

//     void createTextureImageView() {
//         textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_ASPECT_COLOR_BIT);
//     }

//     void createTextureSampler() {
//         VkSamplerCreateInfo samplerInfo{};
//         samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
//         samplerInfo.magFilter = VK_FILTER_LINEAR;
//         samplerInfo.minFilter = VK_FILTER_LINEAR;
//         samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
//         samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
//         samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
//         samplerInfo.anisotropyEnable = VK_TRUE;
//         samplerInfo.maxAnisotropy = 16.0f;
//         samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
//         samplerInfo.unnormalizedCoordinates = VK_FALSE;
//         samplerInfo.compareEnable = VK_FALSE;
//         samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
//         samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
        
//         if (vkCreateSampler(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create texture sampler!");
//         }
//     }

//     void createVertexBuffer() {
//         VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size();
        
//         VkBuffer stagingBuffer;
//         VkDeviceMemory stagingBufferMemory;
//         createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
        
//         void* data;
//         vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
//         memcpy(data, vertices.data(), (size_t) bufferSize);
//         vkUnmapMemory(device, stagingBufferMemory);
        
//         createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vertexBuffer, vertexBufferMemory);
        
//         copyBuffer(stagingBuffer, vertexBuffer, bufferSize);
        
//         vkDestroyBuffer(device, stagingBuffer, nullptr);
//         vkFreeMemory(device, stagingBufferMemory, nullptr);
//     }

//     void createIndexBuffer() {
//         VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();
        
//         VkBuffer stagingBuffer;
//         VkDeviceMemory stagingBufferMemory;
//         createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
        
//         void* data;
//         vkMapMemory(device, stagingBufferMemory, 0, bufferSize, 0, &data);
//         memcpy(data, indices.data(), (size_t) bufferSize);
//         vkUnmapMemory(device, stagingBufferMemory);
        
//         createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory);
        
//         copyBuffer(stagingBuffer, indexBuffer, bufferSize);
        
//         vkDestroyBuffer(device, stagingBuffer, nullptr);
//         vkFreeMemory(device, stagingBufferMemory, nullptr);
//     }

//     void createUniformBuffers() {
//         VkDeviceSize bufferSize = sizeof(UniformBufferObject);
        
//         uniformBuffers.resize(MAX_FRAMES_IN_FLIGHT);
//         uniformBuffersMemory.resize(MAX_FRAMES_IN_FLIGHT);
//         uniformBuffersMapped.resize(MAX_FRAMES_IN_FLIGHT);
        
//         for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
//             createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, uniformBuffers[i], uniformBuffersMemory[i]);
            
//             vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
//         }
//     }

//     void createDescriptorPool() {
//         std::array<VkDescriptorPoolSize, 2> poolSizes{};
//         poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
//         poolSizes[0].descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
//         poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
//         poolSizes[1].descriptorCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
        
//         VkDescriptorPoolCreateInfo poolInfo{};
//         poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
//         poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
//         poolInfo.pPoolSizes = poolSizes.data();
//         poolInfo.maxSets = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
        
//         if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
//             throw std::runtime_error("failed to create descriptor pool!");
//         }
//     }

//     void createDescriptorSet() {
//         std::vector<VkDescriptorSetLayout> layouts(MAX_FRAMES_IN_FLIGHT, descriptorSetLayout);
//         VkDescriptorSetAllocateInfo allocInfo{};
//         allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
//         allocInfo.descriptorPool = descriptorPool;
//         allocInfo.descriptorSetCount = static_cast<uint32_t>(MAX_FRAMES_IN_FLIGHT);
//         allocInfo.pSetLayouts = layouts.data();
        
//         descriptorSets.resize(MAX_FRAMES_IN_FLIGHT);
//         if (vkAllocateDescriptorSets(device, &allocInfo, descriptorSets.data()) != VK_SUCCESS) {
//             throw std::runtime_error("failed to allocate descriptor sets!");
//         }
        
//         for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
//             VkDescriptorBufferInfo bufferInfo{};
//             bufferInfo.buffer = uniformBuffers[i];
//             bufferInfo.offset = 0;
//             bufferInfo.range = sizeof(UniformBufferObject);
            
//             VkDescriptorImageInfo imageInfo{};
//             imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
//             imageInfo.imageView = textureImageView;
//             imageInfo.sampler = textureSampler;
            
//             std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
            
//             descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
//             descriptorWrites[0].dstSet = descriptorSets[i];
//             descriptorWrites[0].dstBinding = 0;
//             descriptorWrites[0].dstArrayElement = 0;
//             descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
//             descriptorWrites[0].descriptorCount = 1;
//             descriptorWrites[0].pBufferInfo = &bufferInfo;
            
//             descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
//             descriptorWrites[1].dstSet = descriptorSets[i];
//             descriptorWrites[1].dstBinding = 1;
//             descriptorWrites[1].dstArrayElement = 0;
//             descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
//             descriptorWrites[1].descriptorCount = 1;
//             descriptorWrites[1].pImageInfo = &imageInfo;
            
//             vkUpdateDescriptorSets(device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
//         }
//     }

//     void createCommandBuffers() {
//         commandBuffers.resize(MAX_FRAMES_IN_FLIGHT);
        
//         VkCommandBufferAllocateInfo allocInfo{};
//         allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
//         allocInfo.commandPool = commandPool;
//         allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
//         allocInfo.commandBufferCount = (uint32_t) commandBuffers.size();
        
//         if (vkAllocateCommandBuffers(device, &allocInfo, commandBuffers.data()) != VK_SUCCESS) {
//             throw std::runtime_error("failed to allocate command buffers!");
//         }
//     }

//     void createSyncObjects() {
//         imageAvailableSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
//         renderFinishedSemaphores.resize(MAX_FRAMES_IN_FLIGHT);
//         inFlightFences.resize(MAX_FRAMES_IN_FLIGHT);
        
//         VkSemaphoreCreateInfo semaphoreInfo{};
//         semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
        
//         VkFenceCreateInfo fenceInfo{};
//         fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
//         fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
        
//         for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
//             if (vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]) != VK_SUCCESS ||
//                 vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]) != VK_SUCCESS ||
//                 vkCreateFence(device, &fenceInfo, nullptr, &inFlightFences[i]) != VK_SUCCESS) {
//                 throw std::runtime_error("failed to create synchronization objects for a frame!");
//             }
//         }
//     }

//     void drawFrame() {
//         vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX);
        
//         uint32_t imageIndex;
//         VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex);
        
//         if (result == VK_ERROR_OUT_OF_DATE_KHR) {
//             recreateSwapChain();
//             return;
//         } else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) {
//             throw std::runtime_error("failed to acquire swap chain image!");
//         }
        
//         updateUniformBuffer(currentFrame);
        
//         vkResetFences(device, 1, &inFlightFences[currentFrame]);
        
//         vkResetCommandBuffer(commandBuffers[currentFrame], 0);
//         recordCommandBuffer(commandBuffers[currentFrame], imageIndex);
        
//         VkSubmitInfo submitInfo{};
//         submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
        
//         VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]};
//         VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
//         submitInfo.waitSemaphoreCount = 1;
//         submitInfo.pWaitSemaphores = waitSemaphores;
//         submitInfo.pWaitDstStageMask = waitStages;
//         submitInfo.commandBufferCount = 1;
//         submitInfo.pCommandBuffers = &commandBuffers[currentFrame];
        
//         VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]};
//         submitInfo.signalSemaphoreCount = 1;
//         submitInfo.pSignalSemaphores = signalSemaphores;
        
//         if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) {
//             throw std::runtime_error("failed to submit draw command buffer!");
//         }
        
//         VkPresentInfoKHR presentInfo{};
//         presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
//         presentInfo.waitSemaphoreCount = 1;
//         presentInfo.pWaitSemaphores = signalSemaphores;
        
//         VkSwapchainKHR swapChains[] = {swapChain};
//         presentInfo.swapchainCount = 1;
//         presentInfo.pSwapchains = swapChains;
//         presentInfo.pImageIndices = &imageIndex;
//         presentInfo.pResults = nullptr;
        
//         result = vkQueuePresentKHR(presentQueue, &presentInfo);
        
//         if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || framebufferResized) {
//             framebufferResized = false;
//             recreateSwapChain();
//         } else if (result != VK_SUCCESS) {
//             throw std::runtime_error("failed to present swap chain image!");
//         }
        
//         currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
//     }

//     void recordCommandBuffer(VkCommandBuffer commandBuffer, uint32_t imageIndex) {
//         VkCommandBufferBeginInfo beginInfo{};
//         beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
//         beginInfo.flags = 0;
//         beginInfo.pInheritanceInfo = nullptr;
        
//         if (vkBeginCommandBuffer(commandBuffer, &beginInfo) != VK_SUCCESS) {
//             throw std::runtime_error("failed to begin recording command buffer!");
//         }
        
//         VkRenderPassBeginInfo renderPassInfo{};
//         renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
//         renderPassInfo.renderPass = renderPass;
//         renderPassInfo.framebuffer = swapChainFramebuffers[imageIndex];
//         renderPassInfo.renderArea.offset = {0, 0};
//         renderPassInfo.renderArea.extent = swapChainExtent;
        
//         VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
//         renderPassInfo.clearValueCount = 1;
//         renderPassInfo.pClearValues = &clearColor;
        
//         vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
//         vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, graphicsPipeline);
        
//         VkViewport viewport{};
//         viewport.x = 0.0f;
//         viewport.y = 0.0f;
//         viewport.width = (float) swapChainExtent.width;
//         viewport.height = (float) swapChainExtent.height;
//         viewport.minDepth = 0.0f;
//         viewport.maxDepth = 1.0f;
//         vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
        
//         VkRect2D scissor{};
//         scissor.offset = {0, 0};
//         scissor.extent = swapChainExtent;
//         vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
        
//         VkBuffer vertexBuffers[] = {vertexBuffer};
//         VkDeviceSize offsets[] = {0};
//         vkCmdBindVertexBuffers(commandBuffer, 0, 1, vertexBuffers, offsets);
//         vkCmdBindIndexBuffer(commandBuffer, indexBuffer, 0, VK_INDEX_TYPE_UINT16);
//         vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descriptorSets[currentFrame], 0, nullptr);
//         vkCmdDrawIndexed(commandBuffer, static_cast<uint32_t>(indices.size()), 1, 0, 0, 0);
//         vkCmdEndRenderPass(commandBuffer);
        
//         if (vkEndCommandBuffer(commandBuffer) != VK_SUCCESS) {
//             throw std::runtime_error("failed to record command buffer!");
//         }
//     }

//     // 辅助函数实现（部分）
//     bool checkValidationLayerSupport() {
//         uint32_t layerCount;
//         vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
        
//         std::vector<VkLayerProperties> availableLayers(layerCount);
//         vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
        
//         for (const char* layerName : validationLayers) {
//             bool layerFound = false;
            
//             for (const auto& layerProperties : availableLayers) {
//                 if (strcmp(layerName, layerProperties.layerName) == 0) {
//                     layerFound = true;
//                     break;
//                 }
//             }
            
//             if (!layerFound) {
//                 return false;
//             }
//         }
        
//         return true;
//     }

//     std::vector<const char*> getRequiredExtensions() {
//         uint32_t glfwExtensionCount = 0;
//         const char** glfwExtensions;
//         glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
        
//         std::vector<const char*> extensions(glfwExtensions, glfwExtensions + glfwExtensionCount);
        
//         if (enableValidationLayers) {
//             extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
//         }
        
//         return extensions;
//     }

//     // 其他辅助函数...
// };

// int main() {
//     HelloTriangleApplication app;
    
//     try {
//         app.run();
//     } catch (const std::exception& e) {
//         std::cerr << e.what() << std::endl;
//         return EXIT_FAILURE;
//     }
    
//     return EXIT_SUCCESS;
// }


// // Uniform 数据
//     struct UniformBufferObject {
//         glm::mat4 model;
//         glm::mat4 view;
//         glm::mat4 proj;
//     };